#include "../include/MyRedis.h"
#include <iostream>


using std::cerr;
using std::endl;
using std::cout;

MyRedis* MyRedis::_pInstance = nullptr;
pthread_once_t MyRedis::_once = PTHREAD_ONCE_INIT;

MyRedis* MyRedis::getInstance() {
    pthread_once(&_once, init);
    return _pInstance;
}

void MyRedis::init() {
    _pInstance = new MyRedis();
    atexit(destroy);
}

void MyRedis::destroy() {
    if(_pInstance) {
        delete _pInstance;
        _pInstance = nullptr;
    }
}

bool MyRedis::connect(const string &ip, int port) {
    _pConnect = redisConnect(ip.c_str(), port);
    if(_pConnect == nullptr) {
        return false;
    }
    if(_pConnect != nullptr && _pConnect->err) {
        cerr << "connect err: " << _pConnect->errstr << endl;
        return false;
    }
    return true;

}

void MyRedis::set(string key, string value) {
    _pReply = (redisReply*)redisCommand(_pConnect, "set %s %s", key.c_str(), value.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "set error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

string MyRedis::get(string key) {
    _pReply = (redisReply*)redisCommand(_pConnect, "get %s", key.c_str());
    if(nullptr == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "get error: " << _pReply->str << endl;
        return "";
    }
    if(_pReply) {
        if(REDIS_REPLY_STRING == _pReply->type) {
            string str = _pReply->str;
            freeReplyObject(_pReply);
            _pReply = nullptr;
            return str;
        }
        else {
            return "";
        }
    }
    else {
        return "";
    }
}

void MyRedis::hset(string table, string key, string value) {
    _pReply = (redisReply*)redisCommand(_pConnect, "hset %s %s %s", table.c_str(), key.c_str(), value.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "hset error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

string MyRedis::hget(string table, string key) {
    _pReply = (redisReply*)redisCommand(_pConnect, "hget %s %s", table.c_str(), key.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "hget error: " << _pReply->str << endl;
        return "";
    }
    if(_pReply) {
        if(REDIS_REPLY_STRING == _pReply->type) {
            string str = _pReply->str;
            freeReplyObject(_pReply);
            _pReply = nullptr;
            return str;
        }
        else {
            return "";
        }
    }
    else {
        return "";
    }
}

void MyRedis::lpush(string key, string value) {
    _pReply = (redisReply*)redisCommand(_pConnect, "lpush %s %s", key.c_str(), value.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "lpush error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::rpush(string key, string value) {
    _pReply = (redisReply*)redisCommand(_pConnect, "rpush %s %s", key.c_str(), value.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "rpush error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::lpop(string key) {
    _pReply = (redisReply*)redisCommand(_pConnect, "lpop %s", key.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "lpop error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::rpop(string key) {
    _pReply = (redisReply*)redisCommand(_pConnect, "rpop %s", key.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "rpop error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::lset(string key, size_t idx, string value) {
    _pReply = (redisReply*)redisCommand(_pConnect, "lset %s %u %s", key.c_str(), idx, value.c_str());
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "lset error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

string MyRedis::lindex(string key, size_t idx) {
    _pReply = (redisReply*)redisCommand(_pConnect, "lindex %s %u", key.c_str(), idx);
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "lindex error: " << _pReply->str << endl;
        return "";
    }
    if(_pReply) {
        if(REDIS_REPLY_STRING == _pReply->type) {
            string str = _pReply->str;
            freeReplyObject(_pReply);
            _pReply = nullptr;
            return str;
        }
        else {
            return "";
        }
    }
    else {
        return "";
    }
}

void MyRedis::multi() {
    _pReply = (redisReply*)redisCommand(_pConnect, "MULTI");
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "multi error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::exec() {
    _pReply = (redisReply*)redisCommand(_pConnect, "exec");
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "exec error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::discard() {
    _pReply = (redisReply*)redisCommand(_pConnect, "discard");
    if(NULL == _pReply && REDIS_REPLY_ERROR == _pReply->type) {
        cerr << "discard error: " << _pReply->str << endl;
        return;
    }
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}

void MyRedis::select(int idx)
{
    _pReply = (redisReply*)redisCommand(_pConnect, "select %d",idx);
    if(_pReply) {
        freeReplyObject(_pReply);
        _pReply = nullptr;
    }
}